package game;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;

public class Grid {
	private int width;
	private int height;
	private int numMines;
	private HashMap<Coordinate, Boolean> coords;

	public Grid(int x, int y, int numMines) {
		setWidth(x);
		setHeight(y);
		setNumMines(numMines);
		coords = new HashMap<Coordinate, Boolean>();
		
		// randomize mine locations
		Random r = new Random();
		for (int k=0; k<numMines; k++) {
			while (true) {
				Coordinate c = new Coordinate(r.nextInt(x), r.nextInt(y));
				if (!(coords.containsKey(c))) {
					coords.put(c, true); 
					break;
				}
			}
		}
		
		for (int i=0; i<width; i++) {
			for (int j=0; j<height; j++) {
				Coordinate c = new Coordinate(i,j);
				if(!(coords.containsKey(c)))
					coords.put(c, false);
			}
		}

	}
	public void setWidth(int width) {
		this.width = width;
	}

	public int getWidth() {
		return width;
	}
	
	public void setHeight(int height) {
		this.height = height;
	}
	
	public int getHeight() {
		return height;
	}
	
	public void setNumMines(int numMines) {
		this.numMines = numMines;
	}
	
	public int getNumMines() {
		return numMines; 
	}
	
	/**
	 * @param x X coordinate
	 * @param y Y coordinate
	 * @return the Coordinate on this Grid with given position (x, y)
	 * returns null if this Coordinate is not in this Grid
	 */
	public Coordinate getCoordinate(int x, int y){
		for (Coordinate c: coords.keySet()){
			if (c.equals(new Coordinate(x, y)))
				return c;
		}
		return null;
	}
	
	/**
	 * @param c Coordinate
	 * @return true if given Coordinate is a mine, 
	 * false if given Coordinate is not a mine
	 */
	public Boolean isMine(Coordinate c) {
		if (!coords.containsKey(c)) return null;
		return coords.get(c);
	}
	
	/**
	 * @param c Coordinate
	 * @param d Direction
	 * @return the neighboring Coordinate on this Grid 
	 * relative to given Coordinate by given Direction
	 */
	public Coordinate getNeighbor(Coordinate c, Direction d) {
		Coordinate cc = new Coordinate(c.getX()+d.getDx(), c.getY()+d.getDy());
		if (coords.containsKey(cc)) return cc;
		else return null;
	}
	
	public Set<Coordinate> getBorderNeighbors(Coordinate c) {
		Set<Coordinate> s = new HashSet<Coordinate>();
		Coordinate cc;
		cc = getNeighbor(c, Direction.NORTH);
		if (cc != null) s.add(cc);
		cc = getNeighbor(c, Direction.EAST);
		if (cc != null) s.add(cc);
		cc = getNeighbor(c, Direction.SOUTH);
		if (cc != null) s.add(cc);
		cc = getNeighbor(c, Direction.WEST);
		if (cc != null) s.add(cc);
		if (!s.isEmpty()) return s;
		else return null;
	}
	
	/**
	 * @param c Coordinate
	 * @return a set of neighboring Coordinates on this Grid around specified Coordinate,
	 * returns null if set is empty
	 */
	public Set<Coordinate> getAllNeighbors(Coordinate c) {
		Set<Coordinate> set = new HashSet<Coordinate>();
		Coordinate cc;
		for (Direction d:Direction.values()) {
			cc = getNeighbor(c, d);
			if (cc != null) set.add(getNeighbor(c, d));
		}
		if (set.isEmpty()) return null;
		else return set;
	}
	
	public int getNumSurMines(Coordinate c) {
		Set<Coordinate> s = getAllNeighbors(c);
		int count = 0;
		if (s != null) {
			for(Coordinate cc:s) {
				if (coords.get(cc)) count++; 
			}
		}
		return count;
	}
}
